#lang sicp
;; Conclusion:

;; *** explicit-dispatch ***
;; 1. when new type must be added:
;; generic procedure of all must be modified that add new condition clause for each 
;; add the predicate and constructor
;; change name to prevent naming conflict
;; 
;; 2. when operation must be added:
;; add new generic procedure, need know all representations, and write condition clause for all
;; all representations add new operation, change operation name to prevent naming conflict
;;
;; *** explicit-dispatch *** END


;; *** data-directed ***
;; 1. when new type must be added:
;; install new type's operation to table
;; add the constructor
;; 
;; 2. when operation must be added:
;; add new generic procedure, and all representations add new operation to table
;;
;; *** data-directed *** END


;; *** message-passing ***
;; 1. when new type must be added:
;; just add a new intelligent object
;; 
;; 2. when operation must be added:
;; add new generic procedure, all intelligent object need to add new operation and a condition clause
;;
;; *** message-passing *** END



;; message passing programming

(define (real-part x) (x 'real-part))
(define (imag-part x) (x 'imag-part))
(define (magnitude x) (x 'magnitude))
(define (angle x) (x 'angle))

;;
(define (make-from-real-imag r i)
  (make-from-real-imag-rectangle r i))

(define (make-from-mag-ang r a)
  (make-from-mag-ang-polar r a))


;;
(define (make-from-mag-ang-polar r a)
  (define (real-part z) (* (magnitude z) (cos (angle z))))
  (define (imag-part z) (* (magnitude z) (sin (angle z))))
  (define (magnitude z) (car z))
  (define (angle z) (cdr z))
  (define (make-from-real-imag x y)
    (cons (sqrt (+ (square x) (square y)))
          (atan y x)))
  (define (make-from-mag-ang r a) (cons r a))
  
  (let ((z (make-from-mag-ang r a)))
    (define (dispatch op)
      (cond ((eq? op 'real-part) (real-part z))
            ((eq? op 'imag-part) (imag-part z))
            ((eq? op 'magnitude) (magnitude z))
            ((eq? op 'angle) (angle z))
            (else "unknowed operation -- make-from-mag-ang-polar" op)))
    dispatch)
)

(define (make-from-real-imag-rectangle x y)
  (define (dispatch op)
    (cond ((eq? op 'real-part) x)
          ((eq? op 'imag-part) y)
          ((eq? op 'magnitude) (sqrt (+ (square x) (square y))))
          ((eq? op 'angle) (atan y x))
          (else (error "Unknown op: MAKE-FROM-REAL-IMAG" op))))
  dispatch)



;;
(define (square x) (* x x))


;; test
(define a (make-from-real-imag 3 4))
(define b (make-from-mag-ang 5 0.927))
